package com.lee.rpc.protocal.code;

import java.util.List;

import com.lee.rpc.protocal.constant.RpcConstant;
import com.lee.rpc.protocal.core.Header;
import com.lee.rpc.protocal.core.ReqType;
import com.lee.rpc.protocal.core.RpcProtocal;
import com.lee.rpc.protocal.core.RpcRequest;
import com.lee.rpc.protocal.core.RpcResponse;
import com.lee.rpc.protocal.serial.ISerializer;
import com.lee.rpc.protocal.serial.SerializerManager;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

public class RpcDecode extends ByteToMessageDecoder{

	@Override
	protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
		// TODO Auto-generated method stub
		//判断可读字节是否小于头的长度
		if(in.readableBytes() < RpcConstant.HEAD_TOTAL_LEN) {
			return;
		}
		
		//标记读指针
		in.markReaderIndex();
		short magic = in.readShort();
		if(magic!=RpcConstant.MAGIC) {
			throw new IllegalArgumentException("参数异常");
		}
		
		byte serialType = in.readByte();
		byte reqType = in.readByte(); 
		long requestId = in.readLong();
		int length = in.readInt();
		
		//如果长度不一致,说明包可能被拆过了,要重新读
		if(in.readableBytes() < length) {
			in.resetReaderIndex();
			return;
		}
		
		byte[] content = new byte[length];
		in.readBytes(content);
		
		Header header = new Header(magic, serialType, reqType, requestId, length);
		
		ISerializer serializer = SerializerManager.getSerializer(serialType);
		ReqType rt = ReqType.findByCode(reqType); 
		switch(rt) {
		case REQUEST: 
			RpcRequest request = serializer.deserialize(content, RpcRequest.class);
			RpcProtocal<RpcRequest> reqProtocal = new RpcProtocal<>();
			reqProtocal.setHeader(header);
			reqProtocal.setContent(request);
			out.add(reqProtocal);
			break;
		case RESPONSE:
			RpcResponse response = serializer.deserialize(content, RpcResponse.class);
			RpcProtocal<RpcResponse> respProtocal = new RpcProtocal<>();
			respProtocal.setHeader(header);
			respProtocal.setContent(response);
			out.add(respProtocal);
			break;
		default:
			break;
		}
		
	}

}
